﻿using System;
using System.Collections.Generic;

using Styx;
using Styx.Net;
using Styx.Net.Services;
using System.Runtime.InteropServices;

namespace Example
{
    [Guid("3C44861C-99EF-454A-9BBC-E995D505062C")]
    [NetworkService(InstanceType = InstanceType.Single)]
    public sealed class StyxNetworkExampleService : IStyxNetworkExampleService, IServiceNotification
    {
        private Dictionary<string, ISession> _users = new Dictionary<string,ISession>();

        public StyxNetworkExampleService()
        {
        }

        public void InitializeSession(ISession session)
        {
        }

        public void UninitializeSession(ISession session)
        {
            string userName = null;

            lock (_users)
            {
                foreach (KeyValuePair<string, ISession> kvp in _users)
                {
                    if (kvp.Value == session)
                    {
                        userName = kvp.Key;
                        break;
                    }
                }

                if (userName == null)
                    return;

                _users.Remove(userName);
            }


            using (NetworkEventContext context = new NetworkEventContext())
            {
                context.ExcludeList.Add(CallingContext.Current.Session);

                if ( UserLeft != null )
                    UserLeft( this, new UserInfoEventArgs(userName));
            }
        }

        public string ServiceName
        {
            get { return "Styx Network Example Service"; }
        }

        public void RegisterUser(string userName)
        {
            lock (_users)
            {
                foreach( KeyValuePair<string, ISession> kvp in _users )
                    if ( kvp.Key == userName || kvp.Value == CallingContext.Current.Session )
                        throw new ArgumentException("The user is already registered", "userName");

                _users.Add(userName, CallingContext.Current.Session);
            }

            using (NetworkEventContext context = new NetworkEventContext())
            {
                context.ExcludeList.Add(CallingContext.Current.Session);

                if (UserArrived != null)
                    UserArrived(this, new UserInfoEventArgs(userName));
            }
        }

        public void UnregisterUser()
        {
            string userName = null;

            lock (_users)
            {
                foreach (KeyValuePair<string, ISession> kvp in _users)
                {
                    if (kvp.Value == CallingContext.Current.Session)
                    {
                        userName = kvp.Key;
                        break;
                    }
                }

                if (userName == null)
                    throw new ArgumentException("The user is not registered yet");

                _users.Remove(userName);
            }

            using (NetworkEventContext context = new NetworkEventContext())
            {
                context.ExcludeList.Add(CallingContext.Current.Session);

                if (UserLeft != null)
                    UserLeft(this, new UserInfoEventArgs(userName));
            }
        }

        public List<string> GetListOfUsers()
        {
            List<string> users = new List<string>();

            lock (_users)
            {
                foreach (KeyValuePair<string, ISession> kvp in _users)
                    users.Add(kvp.Key);
            }

            return users;
        }

        public void SendMessage(string userName, string message)
        {
            ISession session = null;
            string senderUserName = null;

            lock (_users)
            {
                foreach( KeyValuePair<string, ISession> kvp in _users )
                {
                    if ( kvp.Value == CallingContext.Current.Session )
                    {
                        senderUserName = kvp.Key;
                        break;
                    }
                }

                if (senderUserName == null)
                    throw new Exception("You must register user before sending message");

                if (!_users.ContainsKey(userName))
                    throw new ArgumentException("Unknown user", "userName");

                session = _users[userName];
            }

            using (NetworkEventContext context = new NetworkEventContext())
            {
                context.IncludeList.Add(session);

                if (MessageReceived != null)
                    MessageReceived(this, new MessageEventArgs(senderUserName, message));
            }
        }

        public event EventHandler<UserInfoEventArgs> UserArrived;

        public event EventHandler<UserInfoEventArgs> UserLeft;

        public event EventHandler<MessageEventArgs> MessageReceived;
    }
}
